Skip to content

fix: add rail_confirmation_verified to PaymentReceipt (closes #327) - #335

Open
babyblueviper1 wants to merge 2 commits into
google-agentic-commerce:mainfrom
babyblueviper1:fix/receipt-rail-verification
Open

fix: add rail_confirmation_verified to PaymentReceipt (closes #327)#335
babyblueviper1 wants to merge 2 commits into
google-agentic-commerce:mainfrom
babyblueviper1:fix/receipt-rail-verification

Conversation

@babyblueviper1

Copy link
Copy Markdown

What

PaymentReceipt(status="Success") currently asserts payment success purely by producing psp_confirmation_id/network_confirmation_id — the Python SDK's create_payment_receipt() self-generates both as a UUID with no payment-rail check, and the MPP sample signs the result without ever calling out to a PSP or network (#327). A downstream party has no way to tell "independently confirmed against the rail" apart from "the issuer declared success and generated two IDs to satisfy the schema."

This adds an optional rail_confirmation_verified boolean to the Success receipt schema — additive and backward compatible, absent/false is exactly the behavior every existing caller already gets. create_payment_receipt() now accepts optional psp_confirmation_id/network_confirmation_id: omit them and nothing changes; supply real, rail-checked values and the receipt honestly reports rail_confirmation_verified=true.

Deliberately does not try to make the SDK itself perform rail verification — that's business/PSP-specific and out of scope for a spec-level receipt helper. It only stops the receipt from silently implying a check that never happened.

This generalizes the same present-vs-checked distinction this repo's own negotiation-ref.md invariant 5 already establishes — discussed with @giskard09 on #327, who suggested drafting this as a concrete proposal rather than another comment.

How it was built

  • Schema: code/sdk/schemas/ap2/payment_receipt.json — new optional field, no changes to required/oneOf.
  • Regenerated code/sdk/python/ap2/sdk/generated/payment_receipt.py via the documented uv run --with datamodel-code-generator python3 code/sdk/schemas/generate.py, scoped to just this schema's diff (the run also touched every other generated file's regen timestamp plus one unrelated jwk.py behavior difference from a newer datamodel-code-generator version — reverted those, out of scope here).
  • receipt_wrapper.py: two new optional kwargs, both None-default.
  • 2 new tests (test_create_payment_receipt_defaults_to_unverified, test_create_payment_receipt_with_real_rail_confirmation).

Testing

  • receipt_wrapper_tests.py: 10/10 pass (8 existing + 2 new).
  • Full code/sdk/python/ap2/tests/ suite: 188 passed. The 2 failures in kb_sd_jwt_intermediate_tests.py (aud/nonce mismatch) reproduce identically on main before this change — pre-existing, unrelated, already tracked separately as [Bug]: Python terminal KB-SD-JWT verifier accepts tokens missing aud or nonce #319.
  • ruff check / ruff format --diff clean on all touched files.

Fixes #327

@babyblueviper1
babyblueviper1 requested a review from a team as a code owner August 17, 2026 13:21
@google-cla

google-cla Bot commented Aug 17, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@babyblueviper1 babyblueviper1 changed the title Add rail_confirmation_verified to PaymentReceipt (closes #327) fix: add rail_confirmation_verified to PaymentReceipt (closes #327) Aug 17, 2026
@babyblueviper1

Copy link
Copy Markdown
Author

recheck

…onesty gap

PaymentReceipt(status="Success") currently asserts payment success purely by
producing psp_confirmation_id/network_confirmation_id -- the Python SDK's
create_payment_receipt() self-generates both as a UUID with no payment-rail
check, and the sample MPP server signs the result without ever calling out
to a PSP or network. A downstream party has no way to distinguish "this
receipt was independently confirmed against the rail" from "the issuer
declared success and generated two IDs to match the schema."

This adds an optional rail_confirmation_verified boolean to the Success
receipt schema (additive, backward compatible -- absent/false is the exact
behavior every existing caller already gets). create_payment_receipt() now
accepts optional psp_confirmation_id/network_confirmation_id: omit them and
nothing changes; supply real, rail-checked values and the receipt honestly
reports rail_confirmation_verified=true.

This does not attempt to make the SDK itself perform rail verification --
that's necessarily business/PSP-specific and out of scope for a spec-level
receipt helper. It only stops the receipt from silently implying a check
that never happened, generalizing the same present-vs-checked distinction
already converged on in this repo's own negotiation-ref.md invariant 5,
discussed with @giskard09 on google-agentic-commerce#327.

Regenerated code/sdk/python/ap2/sdk/generated/payment_receipt.py via the
documented `uv run --with datamodel-code-generator python3
code/sdk/schemas/generate.py`, scoped to just this schema's diff (other
generated files were reverted -- their regen timestamp bump and one
unrelated jwk.py behavior difference from a newer datamodel-code-generator
version are out of scope for this change).

2 new tests confirm both paths (default-unverified, explicit-verified);
existing receipt_wrapper_tests.py suite (10/10) and the broader test suite
pass -- the only 2 pre-existing failures (kb_sd_jwt_intermediate_tests.py,
aud/nonce mismatch) reproduce identically on main before this change and
are unrelated (tracked separately as google-agentic-commerce#319).

Fixes google-agentic-commerce#327
@babyblueviper1
babyblueviper1 force-pushed the fix/receipt-rail-verification branch from 5466886 to 5e914a4 Compare August 17, 2026 13:33
@giskard09

Copy link
Copy Markdown

Clean scope — additive, backward-compatible, and it's honest about not trying to solve rail verification itself. Good PR.

@babyblueviper1

Copy link
Copy Markdown
Author

recheck

@babyblueviper1

Copy link
Copy Markdown
Author

Thanks — appreciated. Kept it scoped deliberately: this flags the gap (issuer self-declared vs. independently confirmed) without pretending to solve rail verification, which is a separate, harder problem outside what a receipt schema can guarantee on its own.

@babyblueviper1

Copy link
Copy Markdown
Author

CI status update on this PR's two failing checks:

spellcheck — fixed (00e84df). cspell flagged real technical terms as unknown words: pisp/PISP (Payment Initiation Service Provider), SECP (secp256k1), pyca (the pyca/cryptography library this PR's signature verification depends on), and codegen/datamodel (from the generated SDK file's own header comment). Added all to .cspell/custom-words.txt. Verified locally with npx cspell against the exact 4 files this PR touches: 0 issues.

Lint Code Base (Super-Linter/Biome) — pre-existing, unrelated to this diff, not fixed here. The failure is entirely inside docs/assets/mandate_delegation_user_credential.svg (Biome's SVG/XML parser choking on that file's DOCTYPE declaration). This PR never touches that file — confirmed it's unmodified since b4587ac (the v0.2 release commit) and identical on main. Flagging so it isn't misattributed to this change; happy to open a separate PR excluding docs assets from Biome's lint scope (or regenerating the SVG) if that's useful, but didn't want to bundle an unrelated fix into a targeted bugfix PR.

pisp/PISP (Payment Initiation Service Provider), SECP (secp256k1), pyca
(pyca/cryptography, the library this PR's signature verification uses),
codegen/datamodel (from the generated SDK file's own header comment) --
all real terms, not typos. Verified locally: cspell now reports 0 issues
across all 4 files this PR touches.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Payment receipt Success can be issued without payment-rail success evidence

2 participants